home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcl / src-16f.lha / compiler / dump.lisp < prev    next >
Encoding:
Text File  |  1991-12-22  |  42.6 KB  |  1,286 lines

  1. ;;; -*- Package: C; Log: C.Log -*-
  2. ;;;
  3. ;;; **********************************************************************
  4. ;;; This code was written as part of the CMU Common Lisp project at
  5. ;;; Carnegie Mellon University, and has been placed in the public domain.
  6. ;;; If you want to use this code or any part of CMU Common Lisp, please contact
  7. ;;; Scott Fahlman or slisp-group@cs.cmu.edu.
  8. ;;;
  9. (ext:file-comment
  10.   "$Header: dump.lisp,v 1.36 91/12/21 23:07:24 ram Exp $")
  11. ;;;
  12. ;;; **********************************************************************
  13. ;;;
  14. ;;; $Header: dump.lisp,v 1.36 91/12/21 23:07:24 ram Exp $
  15. ;;;
  16. ;;;    This file contains stuff that knows about dumping FASL files.
  17. ;;;
  18. (in-package "C")
  19.  
  20. (proclaim '(special compiler-version))
  21.  
  22. ;;;; Fasl dumper state:
  23.  
  24. ;;; We do some buffering in front of the stream that represents the output file
  25. ;;; so as to speed things up a bit.
  26. ;;;
  27. (defconstant fasl-buffer-size 2048)
  28.  
  29. ;;; The Fasl-File structure represents everything we need to know about dumping
  30. ;;; to a fasl file.  We need to objectify the state, since the fasdumper must
  31. ;;; be reentrant.
  32. ;;;
  33. (defstruct (fasl-file
  34.         (:print-function
  35.          (lambda (s stream d)
  36.            (declare (ignore d) (stream stream))
  37.            (format stream "#<Fasl-File ~S>"
  38.                (namestring (fasl-file-stream s))))))
  39.   ;;
  40.   ;; The stream we dump to.
  41.   (stream (required-argument) :type stream)
  42.   ;;
  43.   ;; The buffer we accumulate output in before blasting it out to the stream
  44.   ;; with SYS:OUTPUT-RAW-BYTES.
  45.   (buffer (make-array fasl-buffer-size :element-type '(unsigned-byte 8))
  46.       :type (simple-array (unsigned-byte 8) (*)))
  47.   ;;
  48.   ;; The index of the first free byte in Buffer.  Note that there is always at
  49.   ;; least one byte free.
  50.   (buffer-index 0 :type index)
  51.   ;;
  52.   ;; Hashtables we use to keep track of dumped constants so that we can get
  53.   ;; them from the table rather than dumping them again.  The EQUAL-TABLE is
  54.   ;; used for lists and strings, and the EQ-TABLE is used for everything else.
  55.   ;; We use a separate EQ table to avoid performance patholigies with objects
  56.   ;; for which EQUAL degnerates to EQL.  Everything entered in the EQUAL table
  57.   ;; is also entered in the EQ table.
  58.   (equal-table (make-hash-table :test #'equal) :type hash-table)
  59.   (eq-table (make-hash-table :test #'eq) :type hash-table)
  60.   ;;
  61.   ;; The table's current free pointer: the next offset to be used.
  62.   (table-free 0 :type index)
  63.   ;;
  64.   ;; Alist (Package . Offset) of the table offsets for each package we have
  65.   ;; currently located.
  66.   (packages () :type list)
  67.   ;;
  68.   ;; Table mapping from the Entry-Info structures for dumped XEPs to the table
  69.   ;; offsets of the corresponding code pointers.
  70.   (entry-table (make-hash-table :test #'eq) :type hash-table)
  71.   ;;
  72.   ;; Table holding back-patching info for forward references to XEPs.  The key
  73.   ;; is the Entry-Info structure for the XEP, and the value is a list of conses
  74.   ;; (<code-handle> . <offset>), where <code-handle> is the offset in the table
  75.   ;; of the code object needing to be patched, and <offset> is the offset that
  76.   ;; must be patched.
  77.   (patch-table (make-hash-table :test #'eq) :type hash-table)
  78.   ;;
  79.   ;; A list of the table handles for all of the DEBUG-INFO structures dumped in
  80.   ;; this file.  These structures must be back-patched with source location
  81.   ;; information when the compilation is complete.
  82.   (debug-info () :type list)
  83.   ;;
  84.   ;; Used to keep track of objects that we are in the process of dumping so
  85.   ;; that circularities can be preserved.  The key is the object that we have
  86.   ;; previously seen, and the value is the object that we reference in the
  87.   ;; table to find this previously seen object.  (The value is never NIL.)
  88.   ;;
  89.   ;; Except with list objects, the key and the value are always the same.  In a
  90.   ;; list, the key will be some tail of the value.
  91.   (circularity-table (make-hash-table :test #'eq) :type hash-table)
  92.   ;;
  93.   ;; Hash table of structures that are allowed to be dumped.  If we try to
  94.   ;; dump a structure that isn't in this hash table, we lose.
  95.   (valid-structures (make-hash-table :test #'eq) :type hash-table))
  96.  
  97. ;;; This structure holds information about a circularity.
  98. ;;;
  99. (defstruct circularity
  100.   ;;
  101.   ;; Kind of modification to make to create circularity.
  102.   (type (required-argument) :type (member :rplaca :rplacd :svset :struct-set))
  103.   ;;
  104.   ;; Object containing circularity.
  105.   object
  106.   ;;
  107.   ;; Index in object for circularity.
  108.   (index (required-argument) :type index)
  109.   ;;
  110.   ;; The object to be stored at Index in Object.  This is that the key that we
  111.   ;; were using when we discovered the circularity.
  112.   value
  113.   ;;
  114.   ;; The value that was associated with Value in the CIRCULARITY-TABLE.  This
  115.   ;; is the object that we look up in the EQ-TABLE to locate Value.
  116.   enclosing-object)
  117.  
  118.  
  119. ;;; A list of the Circularity structures for all of the circularities detected
  120. ;;; in the the current top-level call to Dump-Object.  Setting this lobotomizes
  121. ;;; circularity detection as well, since circular dumping uses the table.
  122. ;;;
  123. (defvar *circularities-detected*)
  124.  
  125.  
  126. ;;; Used to inhibit table access when dumping forms to be read by the cold
  127. ;;; loader.
  128. ;;;
  129. (defvar *cold-load-dump* nil)
  130.  
  131.  
  132. ;;; Used to turn off the structure validation during dumping of source info.
  133. ;;;
  134. (defvar *dump-only-valid-structures* t)
  135.  
  136.  
  137. ;;;; Utilities:
  138.  
  139. ;;; FLUSH-FASL-FILE-BUFFER  --  Internal
  140. ;;;
  141. ;;;    Write out the contents of File's buffer to its stream.
  142. ;;;
  143. (defun flush-fasl-file-buffer (file)
  144.   (system:output-raw-bytes (fasl-file-stream file)
  145.                (fasl-file-buffer file)
  146.                0
  147.                (fasl-file-buffer-index file))
  148.   (setf (fasl-file-buffer-index file) 0)
  149.   (undefined-value))
  150.  
  151.  
  152. ;;; Dump-Byte  --  Internal
  153. ;;;
  154. ;;;    Write the byte B to the specified fasl-file stream.
  155. ;;;
  156. (declaim (maybe-inline dump-byte))
  157. (defun dump-byte (b file)
  158.   (declare (type (unsigned-byte 8) b) (type fasl-file file)
  159.        (optimize (speed 3) (safety 0)))
  160.   (let ((idx (fasl-file-buffer-index file))
  161.     (buf (fasl-file-buffer file)))
  162.     (setf (aref buf idx) b)
  163.     (let ((new (1+ idx)))
  164.       (setf (fasl-file-buffer-index file) new)
  165.       (when (= new fasl-buffer-size)
  166.     (flush-fasl-file-buffer file))))
  167.   (undefined-value))
  168.  
  169.  
  170. ;;; DUMP-UNSIGNED-32  --  Internal
  171. ;;;
  172. ;;;    Dump a 4 byte unsigned integer.
  173. ;;;
  174. (defun dump-unsigned-32 (num file)
  175.   (declare (type (unsigned-byte 32) num) (type fasl-file file)
  176.        (optimize (speed 3) (safety 0)))
  177.   (let* ((idx (fasl-file-buffer-index file))
  178.      (buf (fasl-file-buffer file))
  179.      (new (+ idx 4)))
  180.     (when (>= new fasl-buffer-size)
  181.       (flush-fasl-file-buffer file)
  182.       (setq idx 0  new 4))
  183.     (setf (aref buf (+ idx 0)) (ldb (byte 8 0) num))
  184.     (setf (aref buf (+ idx 1)) (ldb (byte 8 8) num))
  185.     (setf (aref buf (+ idx 2)) (ldb (byte 8 16) num))
  186.     (setf (aref buf (+ idx 3)) (ldb (byte 8 24) num))
  187.     (setf (fasl-file-buffer-index file) new))
  188.   (undefined-value))
  189.  
  190.  
  191. ;;; Dump-Var-Signed   --  Internal
  192. ;;;
  193. ;;;    Dump Num to the fasl stream, represented by the specified number of
  194. ;;; bytes.
  195. ;;;
  196. (defun dump-var-signed  (num bytes file)
  197.   (declare (integer num) (type index bytes) (type fasl-file file)
  198.        (inline dump-byte))
  199.   (do ((n num (ash n -8))
  200.        (i bytes (1- i)))
  201.       ((= i 0))
  202.     (declare (type index i))
  203.     (dump-byte (logand n #xFF) file))
  204.   (undefined-value))
  205.  
  206.  
  207. ;;; DUMP-BYTES  --  Internal
  208. ;;;
  209. ;;;    Dump the first N bytes in Vec out to File.  Vec is some sort of unboxed
  210. ;;; vector-like thing that we can BLT from.
  211. ;;;
  212. (defun dump-bytes (vec n file)
  213.   (declare (type index n) (type fasl-file file)
  214.        (optimize (speed 3) (safety 0)))
  215.   (let* ((idx (fasl-file-buffer-index file))
  216.      (buf (fasl-file-buffer file))
  217.      (new (+ idx n)))
  218.     (cond ((< new fasl-buffer-size)
  219.        (bit-bash-copy vec vector-data-bit-offset
  220.               buf
  221.               (+ vector-data-bit-offset
  222.                  (the index (* idx vm:byte-bits)))
  223.               (* n vm:byte-bits))
  224.        (setf (fasl-file-buffer-index file) new))
  225.       (t
  226.        (flush-fasl-file-buffer file)
  227.        (cond ((>= n fasl-buffer-size)
  228.           (system:output-raw-bytes (fasl-file-stream file)
  229.                        vec 0 n))
  230.          (t
  231.           (bit-bash-copy vec vector-data-bit-offset
  232.                  buf vector-data-bit-offset
  233.                  (* n vm:byte-bits))
  234.           (setf (fasl-file-buffer-index file) n))))))
  235.   (undefined-value))
  236.  
  237.  
  238. ;;; Dump-FOP  --  Internal
  239. ;;;
  240. ;;;    Dump the FOP code for the named FOP to the specified fasl-file.
  241. ;;;
  242. (defmacro dump-fop (fs file)
  243.   (let* ((fs (eval fs))
  244.      (val (get fs 'lisp::fop-code)))
  245.     (assert val () "Compiler bug: ~S not a legal fasload operator." fs)
  246.     `(dump-byte ',val ,file)))
  247.  
  248.  
  249. ;;; Dump-FOP*  --  Internal
  250. ;;;
  251. ;;;    Dump a FOP-Code along with an integer argument, choosing the FOP based
  252. ;;; on whether the argument will fit in a single byte.
  253. ;;;
  254. (defmacro dump-fop* (n byte-fop word-fop file)
  255.   (once-only ((n-n n)
  256.           (n-file file))
  257.     `(cond ((< ,n-n 256)
  258.         (dump-fop ',byte-fop ,n-file)
  259.         (dump-byte ,n-n ,n-file))
  260.        (t
  261.         (dump-fop ',word-fop ,n-file)
  262.         (dump-unsigned-32 ,n-n ,n-file)))))
  263.  
  264.  
  265. ;;; Dump-Push  --  Internal
  266. ;;;
  267. ;;;    Push the object at table offset Handle on the fasl stack.
  268. ;;;
  269. (defun dump-push (handle file)
  270.   (declare (type index handle) (type fasl-file file))
  271.   (dump-fop* handle lisp::fop-byte-push lisp::fop-push file)
  272.   (undefined-value))
  273.  
  274.  
  275. ;;; Dump-Pop  --  Internal
  276. ;;;
  277. ;;;    Pop the object currently on the fasl stack top into the table, and
  278. ;;; return the table index, incrementing the free pointer.
  279. ;;;
  280. (defun dump-pop (file)
  281.   (prog1 (fasl-file-table-free file)
  282.     (dump-fop 'lisp::fop-pop file)
  283.     (incf (fasl-file-table-free file))))
  284.  
  285.  
  286. ;;; EQUAL-CHECK-TABLE  --  Internal
  287. ;;;
  288. ;;;    If X is in File's EQUAL-TABLE, then push the object and return T,
  289. ;;; otherwise NIL.  If *COLD-LOAD-DUMP* is true, then do nothing and return
  290. ;;; NIL.
  291. ;;;
  292. (defun equal-check-table (x file)
  293.   (declare (type fasl-file file))
  294.   (unless *cold-load-dump*
  295.     (let ((handle (gethash x (fasl-file-equal-table file))))
  296.       (cond (handle
  297.          (dump-push handle file)
  298.          t)
  299.         (t
  300.          nil)))))
  301.  
  302.  
  303. ;;; EQ-SAVE-OBJECT, EQUAL-SAVE-OBJECT  --  Internal
  304. ;;;
  305. ;;;    These functions are called after dumping an object to save the object in
  306. ;;; the table.  The object (also passed in as X) must already be on the top of
  307. ;;; the FOP stack.  If *COLD-LOAD-DUMP* is true, then we don't do anything.
  308. ;;;
  309. (defun eq-save-object (x file)
  310.   (declare (type fasl-file file))
  311.   (unless *cold-load-dump*
  312.     (let ((handle (dump-pop file)))
  313.       (setf (gethash x (fasl-file-eq-table file)) handle)
  314.       (dump-push handle file)))
  315.   (undefined-value))
  316. ;;;
  317. (defun equal-save-object (x file)
  318.   (declare (type fasl-file file))
  319.   (unless *cold-load-dump*
  320.     (let ((handle (dump-pop file)))
  321.       (setf (gethash x (fasl-file-equal-table file)) handle)
  322.       (setf (gethash x (fasl-file-eq-table file)) handle)
  323.       (dump-push handle file)))
  324.   (undefined-value))
  325.  
  326.  
  327. ;;; NOTE-POTENTIAL-CIRCULARITY  --  Internal
  328. ;;;
  329. ;;;    Record X in File's CIRCULARITY-TABLE unless *COLD-LOAD-DUMP* is true.
  330. ;;; This is called on objects that we are about to dump might have a circular
  331. ;;; path through them.
  332. ;;;
  333. ;;; The object must not currently be in this table, since the dumper should
  334. ;;; never be recursively called on a circular reference.  Instead, the dumping
  335. ;;; function must detect the circularity and arrange for the dumped object to
  336. ;;; be patched.
  337. ;;;
  338. (defun note-potential-circularity (x file)
  339.   (unless *cold-load-dump*
  340.     (let ((circ (fasl-file-circularity-table file)))
  341.       (assert (not (gethash x circ)))
  342.       (setf (gethash x circ) x)))
  343.   (undefined-value))
  344.  
  345.  
  346. ;;; Fasl-Dump-Cold-Load-Form  --  Interface
  347. ;;;
  348. ;;;    Dump Form to a fasl file so that it evaluated at load time in normal
  349. ;;; load and at cold-load time in cold load.  This is used to dump package
  350. ;;; frobbing forms.
  351. ;;;
  352. (defun fasl-dump-cold-load-form (form file)
  353.   (declare (type fasl-file file))
  354.   (dump-fop 'lisp::fop-normal-load file)
  355.   (let ((*cold-load-dump* t))
  356.     (dump-object form file))
  357.   (dump-fop 'lisp::fop-eval-for-effect file)
  358.   (dump-fop 'lisp::fop-maybe-cold-load file)
  359.   (undefined-value))
  360.  
  361.  
  362. ;;;; Opening and closing:
  363.  
  364. ;;; Open-Fasl-File  --  Interface
  365. ;;;
  366. ;;;    Return a Fasl-File object for dumping to the named file.  Some
  367. ;;; information about the source is specified by the string Where.
  368. ;;;
  369. (defun open-fasl-file (name where)
  370.   (declare (type pathname name))
  371.   (let* ((stream (open name :direction :output
  372.                :if-exists :new-version
  373.                :element-type '(unsigned-byte 8)))
  374.      (res (make-fasl-file :stream stream)))
  375.     (format stream
  376.         "FASL FILE output from ~A.~@
  377.         Compiled ~A on ~A~@
  378.         Compiler ~A, Lisp ~A~@
  379.         Targeted for ~A, FASL version ~D~%"
  380.         where
  381.         (ext:format-universal-time nil (get-universal-time))
  382.         (machine-instance) compiler-version
  383.         (lisp-implementation-version)
  384.         (backend-version *backend*)
  385.         (backend-fasl-file-version *backend*))
  386.     ;;
  387.     ;; Terminate header.
  388.     (dump-byte 255 res)
  389.     ;;
  390.     ;; Specify code format.
  391.     (dump-fop 'lisp::fop-code-format res)
  392.     (dump-byte (backend-fasl-file-implementation *backend*) res)
  393.     (dump-byte (backend-fasl-file-version *backend*) res)
  394.  
  395.     res))
  396.  
  397.  
  398. ;;; Close-Fasl-File  --  Interface
  399. ;;;
  400. ;;;    Close the specified Fasl-File, aborting the write if Abort-P is true.
  401. ;;; We do various sanity checks, then end the group.
  402. ;;;
  403. (defun close-fasl-file (file abort-p)
  404.   (declare (type fasl-file file))
  405.   (assert (zerop (hash-table-count (fasl-file-patch-table file))))
  406.   (dump-fop 'lisp::fop-verify-empty-stack file)
  407.   (dump-fop 'lisp::fop-verify-table-size file)
  408.   (dump-unsigned-32 (fasl-file-table-free file) file)
  409.   (dump-fop 'lisp::fop-end-group file)
  410.   (flush-fasl-file-buffer file)
  411.   (close (fasl-file-stream file) :abort abort-p)
  412.   (undefined-value))
  413.  
  414.  
  415. ;;;; Component (function) dumping:
  416.  
  417. ;;; Dump-Code-Object  --  Internal
  418. ;;;
  419. ;;;    Dump out the constant pool and code-vector for component, push the
  420. ;;; result in the table and return the offset.
  421. ;;;
  422. ;;;    The only tricky thing is handling constant-pool references to functions.
  423. ;;; If we have already dumped the function, then we just push the code pointer.
  424. ;;; Otherwise, we must create back-patching information so that the constant
  425. ;;; will be set when the function is eventually dumped.  This is a bit awkward,
  426. ;;; since we don't have the handle for the code object being dumped while we
  427. ;;; are dumping its constants.
  428. ;;;
  429. ;;;    We dump a trap object as a placeholder for the code vector, which is
  430. ;;; actually filled in by the loader.
  431. ;;;
  432. (defun dump-code-object (component code-segment code-length trace-table file)
  433.   (declare (type component component) (type fasl-file file)
  434.        (list trace-table) (type index code-length))
  435.   (let* ((2comp (component-info component))
  436.      (constants (ir2-component-constants 2comp))
  437.      (num-consts (length constants))
  438.      (trace-table (pack-trace-table trace-table))
  439.      (trace-table-length (length trace-table))
  440.      (total-length (+ code-length (* trace-table-length 2))))
  441.     (collect ((patches))
  442.       ;; Dump the offset of the trace table.
  443.       (dump-object code-length file)
  444.  
  445.       ;; Dump the constants, noting any :entries that have to be fixed up.
  446.       (do ((i vm:code-constants-offset (1+ i)))
  447.       ((>= i num-consts))
  448.     (let ((entry (aref constants i)))
  449.       (etypecase entry
  450.         (constant
  451.          (dump-object (constant-value entry) file))
  452.         (cons
  453.          (ecase (car entry)
  454.            (:entry
  455.         (let* ((info (leaf-info (cdr entry)))
  456.                (handle (gethash info (fasl-file-entry-table file))))
  457.           (cond
  458.            (handle
  459.             (dump-push handle file))
  460.            (t
  461.             (patches (cons info i))
  462.             (dump-fop 'lisp::fop-misc-trap file)))))
  463.            (:load-time-value
  464.         (dump-push (cdr entry) file))))
  465.         (null
  466.          (dump-fop 'lisp::fop-misc-trap file)))))
  467.  
  468.       ;; Dump the debug info.
  469.       (let ((info (debug-info-for-component component))
  470.         (*dump-only-valid-structures* nil))
  471.     (dump-object info file)
  472.     (let ((info-handle (dump-pop file)))
  473.       (dump-push info-handle file)
  474.       (push info-handle (fasl-file-debug-info file))))
  475.  
  476.       (let ((num-consts (- num-consts vm:code-trace-table-offset-slot)))
  477.     (cond ((and (< num-consts #x100) (< total-length #x10000))
  478.            (dump-fop 'lisp::fop-small-code file)
  479.            (dump-byte num-consts file)
  480.            (dump-var-signed total-length 2 file))
  481.           (t
  482.            (dump-fop 'lisp::fop-code file)
  483.            (dump-unsigned-32 num-consts file)
  484.            (dump-unsigned-32 total-length file))))
  485.  
  486.       (flush-fasl-file-buffer file)
  487.       (let ((fixups (emit-code-vector (fasl-file-stream file) code-segment)))
  488.     (dump-i-vector trace-table file t)
  489.     (let ((handle (dump-pop file)))
  490.       (dump-fixups handle fixups file)
  491.       (dolist (patch (patches))
  492.         (push (cons handle (cdr patch))
  493.           (gethash (car patch) (fasl-file-patch-table file))))
  494.       handle)))))
  495.  
  496.  
  497. (defun dump-assembler-routines (code-segment length routines file)
  498.   (dump-fop 'lisp::fop-assembler-code file)
  499.   (dump-unsigned-32 length file)
  500.   (flush-fasl-file-buffer file)
  501.   (let ((fixups (emit-code-vector (fasl-file-stream file) code-segment)))
  502.     (dolist (routine routines)
  503.       (dump-fop 'lisp::fop-normal-load file)
  504.       (let ((*cold-load-dump* t))
  505.     (dump-object (car routine) file))
  506.       (dump-fop 'lisp::fop-maybe-cold-load file)
  507.       (dump-fop 'lisp::fop-assembler-routine file)
  508.       (dump-unsigned-32 (label-position (cdr routine)) file))
  509.     (let ((handle (dump-pop file)))
  510.       (dump-fixups handle fixups file)
  511.       handle)))
  512.  
  513. ;;; Dump-Fixups  --  Internal
  514. ;;;
  515. ;;;    Dump all the fixups.  Currently there are only miscop fixups, and we
  516. ;;; always access them by name rather than number.  There is no reason for
  517. ;;; using miscop numbers other than a minor load-time efficiency win.
  518. ;;;
  519. (defun dump-fixups (code-handle fixups file)
  520.   (declare (type index code-handle) (list fixups)
  521.        (type fasl-file file))
  522.   (when fixups
  523.     (dump-push code-handle file)
  524.     (dolist (info fixups)
  525.       (let* ((kind (first info))
  526.          (fixup (second info))
  527.          (name (fixup-name fixup))
  528.          (flavor (fixup-flavor fixup))
  529.          (offset (third info)))
  530.     (dump-fop 'lisp::fop-normal-load file)
  531.     (let ((*cold-load-dump* t))
  532.       (dump-object kind file))
  533.     (dump-fop 'lisp::fop-maybe-cold-load file)
  534.     (ecase flavor
  535.       (:assembly-routine
  536.        (assert (symbolp name))
  537.        (dump-fop 'lisp::fop-normal-load file)
  538.        (let ((*cold-load-dump* t))
  539.          (dump-object name file))
  540.        (dump-fop 'lisp::fop-maybe-cold-load file)
  541.        (dump-fop 'lisp::fop-assembler-fixup file))
  542.       (:foreign
  543.        (assert (stringp name))
  544.        (dump-fop 'lisp::fop-foreign-fixup file)
  545.        (let ((len (length name)))
  546.          (assert (< len 256))
  547.          (dump-byte len file)
  548.          (dotimes (i len)
  549.            (dump-byte (char-code (schar name i)) file)))))
  550.     (dump-unsigned-32 offset file)))
  551.     (dump-fop 'lisp::fop-pop-for-effect file))
  552.   (undefined-value))
  553.  
  554.  
  555. ;;; Dump-One-Entry  --  Internal
  556. ;;;
  557. ;;;    Dump a function-entry data structure corresponding to Entry to File.
  558. ;;; Code-Handle is the table offset of the code object for the component.
  559. ;;;
  560. ;;; If the entry is a DEFUN, then we also dump a FOP-FSET so that the cold
  561. ;;; loader can instantiate the definition at cold-load time, allowing forward
  562. ;;; references to functions in top-level forms.
  563. ;;;
  564. (defun dump-one-entry (entry code-handle file)
  565.   (declare (type entry-info entry) (type index code-handle)
  566.        (type fasl-file file))
  567.   (let ((name (entry-info-name entry)))
  568.     (dump-push code-handle file)
  569.     (dump-object name file)
  570.     (dump-object (entry-info-arguments entry) file)
  571.     (dump-object (entry-info-type entry) file)
  572.     (dump-fop 'lisp::fop-function-entry file)
  573.     (dump-unsigned-32 (label-position (entry-info-offset entry)) file)
  574.     (let ((handle (dump-pop file)))
  575.       (when (and name (symbolp name))
  576.     (dump-object name file)
  577.     (dump-push handle file)
  578.     (dump-fop 'lisp::fop-fset file))
  579.       handle)))
  580.  
  581. ;;; Alter-Code-Object  --  Internal
  582. ;;;
  583. ;;;    Alter the code object referenced by Code-Handle at the specified Offset,
  584. ;;; storing the object referenced by Entry-Handle.
  585. ;;;
  586. (defun alter-code-object (code-handle offset entry-handle file)
  587.   (declare (type index code-handle entry-handle offset) (type fasl-file file))
  588.   (dump-push code-handle file)
  589.   (dump-push entry-handle file)
  590.   (dump-fop* offset lisp::fop-byte-alter-code lisp::fop-alter-code file)
  591.   (undefined-value))
  592.  
  593.  
  594. ;;; Fasl-Dump-Component  --  Interface
  595. ;;;
  596. ;;;    Dump the code, constants, etc. for component.  We pass in the assembler
  597. ;;; fixups, code vector and node info.
  598. ;;;
  599. (defun fasl-dump-component (component code-segment length trace-table file)
  600.   (declare (type component component) (list trace-table) (type fasl-file file))
  601.  
  602.   (dump-fop 'lisp::fop-verify-empty-stack file)
  603.   (dump-fop 'lisp::fop-verify-table-size file)
  604.   (dump-unsigned-32 (fasl-file-table-free file) file)
  605.  
  606.   (let ((code-handle (dump-code-object component code-segment
  607.                        length trace-table file))
  608.     (2comp (component-info component)))
  609.     (dump-fop 'lisp::fop-verify-empty-stack file)
  610.  
  611.     (dolist (entry (ir2-component-entries 2comp))
  612.       (let ((entry-handle (dump-one-entry entry code-handle file)))
  613.     (setf (gethash entry (fasl-file-entry-table file)) entry-handle)
  614.  
  615.     (let ((old (gethash entry (fasl-file-patch-table file))))
  616.       (when old
  617.         (dolist (patch old)
  618.           (alter-code-object (car patch) (cdr patch) entry-handle file))
  619.         (remhash entry (fasl-file-patch-table file)))))))
  620.   (undefined-value))
  621.  
  622.  
  623. ;;; FASL-DUMP-TOP-LEVEL-LAMBDA-CALL  --  Interface
  624. ;;;
  625. ;;;    Dump a FOP-FUNCALL to call an already dumped top-level lambda at load
  626. ;;; time.  
  627. ;;;
  628. (defun fasl-dump-top-level-lambda-call (fun file)
  629.   (declare (type clambda fun) (type fasl-file file))
  630.   (let ((handle (gethash (leaf-info fun) (fasl-file-entry-table file))))
  631.     (assert handle)
  632.     (dump-push handle file)
  633.     (dump-fop 'lisp::fop-funcall-for-effect file)
  634.     (dump-byte 0 file))
  635.   (undefined-value))
  636.  
  637.  
  638. ;;; FASL-DUMP-SOURCE-INFO  --  Interface
  639. ;;;
  640. ;;;    Compute the correct list of DEBUG-SOURCE structures and backpatch all of
  641. ;;; the dumped DEBUG-INFO structures.  We clear the FASL-FILE-DEBUG-INFO,
  642. ;;; so that subsequent components with different source info may be dumped.
  643. ;;;
  644. (defun fasl-dump-source-info (info file)
  645.   (declare (type source-info info) (type fasl-file file))
  646.   (let ((res (debug-source-for-info info))
  647.     (*dump-only-valid-structures* nil))
  648.     (dump-object res file)
  649.     (let ((res-handle (dump-pop file)))
  650.       (dolist (info-handle (fasl-file-debug-info file))
  651.     (dump-push res-handle file)
  652.     (dump-fop 'lisp::fop-structset file)
  653.     (dump-unsigned-32 info-handle file)
  654.     (dump-unsigned-32 2 file))))
  655.  
  656.   (setf (fasl-file-debug-info file) ())
  657.   (undefined-value))
  658.  
  659.  
  660. ;;;; Main entries to object dumping:
  661.  
  662. ;;; Dump-Non-Immediate-Object  --  Internal
  663. ;;;
  664. ;;;    This function deals with dumping objects that are complex enough so that
  665. ;;; we want to cache them in the table, rather than repeatedly dumping them.
  666. ;;; If the object is in the EQ-TABLE, then we push it, otherwise, we do a type
  667. ;;; dispatch to a type specific dumping function.  The type specific branches
  668. ;;; do any appropriate EQUAL-TABLE check and table entry.
  669. ;;;
  670. ;;;    When we go to dump the object, we enter it in the CIRCULARITY-TABLE.
  671. ;;;
  672. (defun dump-non-immediate-object (x file)
  673.   (let ((index (gethash x (fasl-file-eq-table file))))
  674.     (cond ((and index (not *cold-load-dump*))
  675.        (dump-push index file))
  676.       (t
  677.        (typecase x
  678.          (symbol (dump-symbol x file))
  679.          (list
  680.           (unless (equal-check-table x file)
  681.         (dump-list x file)
  682.         (equal-save-object x file)))
  683.          (structure
  684.           (dump-structure x file)
  685.           (eq-save-object x file))
  686.          (array
  687.           (dump-array x file))
  688.          (number
  689.           (unless (equal-check-table x file)
  690.         (etypecase x
  691.           (ratio (dump-ratio x file))
  692.           (complex (dump-complex x file))
  693.           (float (dump-float x file))
  694.           (integer (dump-integer x file)))
  695.         (equal-save-object x file)))
  696.          (t
  697.           ;;
  698.           ;; This probably never happens, since bad things are detected
  699.           ;; during IR1 conversion.
  700.           (error "This object cannot be dumped into a fasl file:~% ~S"
  701.              x))))))
  702.   (undefined-value))
  703.  
  704.  
  705. ;;; Sub-Dump-Object  --  Internal
  706. ;;;
  707. ;;;    Dump an object of any type by dispatching to the correct type-specific
  708. ;;; dumping function.  We pick off immediate objects, symbols and and magic
  709. ;;; lists here.  Other objects are handled by Dump-Non-Immediate-Object.
  710. ;;;
  711. ;;; This is the function used for recursive calls to the fasl dumper.  We don't
  712. ;;; worry about creating circularities here, since it is assumed that there is
  713. ;;; a top-level call to Dump-Object.
  714. ;;;
  715. (defun sub-dump-object (x file)
  716.   (cond ((listp x)
  717.      (if x
  718.          (dump-non-immediate-object x file)
  719.          (dump-fop 'lisp::fop-empty-list file)))
  720.     ((symbolp x)
  721.      (if (eq x t)
  722.          (dump-fop 'lisp::fop-truth file)
  723.          (dump-non-immediate-object x file)))
  724.     ((fixnump x) (dump-integer x file))
  725.     ((characterp x) (dump-character x file))
  726.     (t
  727.      (dump-non-immediate-object x file))))
  728.  
  729.  
  730. ;;; Dump-Circularities  --  Internal
  731. ;;;
  732. ;;;    Dump stuff to backpatch already dumped objects.  Infos is the list of
  733. ;;; Circularity structures describing what to do.  The patching FOPs take the
  734. ;;; value to store on the stack.  We compute this value by fetching the
  735. ;;; enclosing object from the table, and then CDR'ing it if necessary.
  736. ;;;
  737. (defun dump-circularities (infos file)
  738.   (let ((table (fasl-file-eq-table file)))
  739.     (dolist (info infos)
  740.       (let* ((value (circularity-value info))
  741.          (enclosing (circularity-enclosing-object info)))
  742.     (dump-push (gethash enclosing table) file)
  743.     (unless (eq enclosing value)
  744.       (do ((current enclosing (cdr current))
  745.            (i 0 (1+ i)))
  746.           ((eq current value)
  747.            (dump-fop 'lisp::fop-nthcdr file)
  748.            (dump-unsigned-32 i file))
  749.         (declare (type index i)))))
  750.       
  751.       (ecase (circularity-type info)
  752.     (:rplaca (dump-fop 'lisp::fop-rplaca file))
  753.     (:rplacd (dump-fop 'lisp::fop-rplacd file))
  754.     (:svset (dump-fop 'lisp::fop-svset file))
  755.     (:struct-set (dump-fop 'lisp::fop-structset file)))
  756.       (dump-unsigned-32 (gethash (circularity-object info) table) file)
  757.       (dump-unsigned-32 (circularity-index info) file))))
  758.  
  759.  
  760. ;;; Dump-Object  -- Interface
  761. ;;;
  762. ;;;    Set up stuff for circularity detection, then dump an object.  All shared
  763. ;;; and circular structure will be exactly preserved within a single call to
  764. ;;; Dump-Object.  Sharing between objects dumped by separate calls is only
  765. ;;; preserved when convenient.
  766. ;;;
  767. ;;;    We peek at the objec type so that we only pay the circular detection
  768. ;;; overhead on types of objects that might be circular.
  769. ;;;
  770. (defun dump-object (x file)
  771.   (if (or (array-header-p x) (simple-vector-p x) (consp x) (structurep x))
  772.       (let ((*circularities-detected* ())
  773.         (circ (fasl-file-circularity-table file)))
  774.     (clrhash circ)
  775.     (sub-dump-object x file)
  776.     (when *circularities-detected*
  777.       (dump-circularities *circularities-detected* file)
  778.       (clrhash circ)))
  779.       (sub-dump-object x file)))
  780.  
  781.  
  782. ;;;; Load-time-value and make-load-form support.
  783.  
  784. ;;; FASL-DUMP-LOAD-TIME-VALUE-LAMBDA -- interface.
  785. ;;;
  786. ;;; Emit a funcall of the function and return the handle for the result.
  787. ;;;
  788. (defun fasl-dump-load-time-value-lambda (fun file)
  789.   (declare (type clambda fun) (type fasl-file file))
  790.   (let ((handle (gethash (leaf-info fun) (fasl-file-entry-table file))))
  791.     (assert handle)
  792.     (dump-push handle file)
  793.     (dump-fop 'lisp::fop-funcall file)
  794.     (dump-byte 0 file))
  795.   (dump-pop file))
  796.  
  797. ;;; FASL-CONSTANT-ALREADY-DUMPED -- interface.
  798. ;;;
  799. ;;; Return T iff CONSTANT has not already been dumped.  It's been dumped
  800. ;;; if it's in the EQ table.
  801. ;;; 
  802. (defun fasl-constant-already-dumped (constant file)
  803.   (if (or (gethash constant (fasl-file-eq-table file))
  804.       (gethash constant (fasl-file-valid-structures file)))
  805.       t
  806.       nil))
  807.  
  808. ;;; FASL-NOTE-HANDLE-FOR-CONSTANT -- interface.
  809. ;;;
  810. ;;; Use HANDLE whenever we try to dump CONSTANT.  HANDLE should have been
  811. ;;; returned earlier by FASL-DUMP-LOAD-TIME-VALUE-LAMBDA.
  812. ;;;
  813. (defun fasl-note-handle-for-constant (constant handle file)
  814.   (let ((table (fasl-file-eq-table file)))
  815.     (when (gethash constant table)
  816.       (error "~S already dumped?" constant))
  817.     (setf (gethash constant table) handle))
  818.   (undefined-value))
  819.  
  820. ;;; FASL-VALIDATE-STRUCTURE -- interface.
  821. ;;;
  822. ;;; Note that the specified structure can just be dumped by enumerating the
  823. ;;; slots.
  824. ;;; 
  825. (defun fasl-validate-structure (structure file)
  826.   (setf (gethash structure (fasl-file-valid-structures file)) t)
  827.   (undefined-value))
  828.  
  829.  
  830.  
  831. ;;;; Number Dumping:
  832.  
  833. ;;; Dump a ratio
  834.  
  835. (defun dump-ratio (x file)
  836.   (sub-dump-object (numerator x) file)
  837.   (sub-dump-object (denominator x) file)
  838.   (dump-fop 'lisp::fop-ratio file))
  839.  
  840. ;;; Or a complex...
  841.  
  842. (defun dump-complex (x file)
  843.   (sub-dump-object (realpart x) file)
  844.   (sub-dump-object (imagpart x) file)
  845.   (dump-fop 'lisp::fop-complex file))
  846.  
  847.  
  848. ;;; Dump an integer.
  849.  
  850. (defun dump-integer (n file)
  851.   (typecase n
  852.     ((signed-byte 8)
  853.      (dump-fop 'lisp::fop-byte-integer file)
  854.      (dump-byte (logand #xFF n) file))
  855.     ((unsigned-byte 31)
  856.      (dump-fop 'lisp::fop-word-integer file)
  857.      (dump-unsigned-32 n file))
  858.     ((signed-byte 32)
  859.      (dump-fop 'lisp::fop-word-integer file)
  860.      (dump-var-signed n 4 file))
  861.     (t
  862.      (let ((bytes (ceiling (1+ (integer-length n)) 8)))
  863.        (dump-fop* bytes lisp::fop-small-integer lisp::fop-integer file)
  864.        (dump-var-signed n bytes file)))))
  865.  
  866. (defun dump-float (x file)
  867.   (etypecase x
  868.     (single-float
  869.      (dump-fop 'lisp::fop-single-float file)
  870.      (dump-var-signed (single-float-bits x) 4 file))
  871.     (double-float
  872.      (dump-fop 'lisp::fop-double-float file)
  873.      (let ((x x))
  874.        (declare (double-float x))
  875.        (dump-unsigned-32 (double-float-low-bits x) file)
  876.        (dump-var-signed (double-float-high-bits x) 4 file)))))
  877.  
  878.  
  879. ;;;; Symbol Dumping:
  880.  
  881. ;;; Dump-Package  --  Internal
  882. ;;;
  883. ;;;    Return the table index of Pkg, adding the package to the table if
  884. ;;; necessary.  During cold load, we read the string as a normal string so that
  885. ;;; we can do the package lookup at cold load time.
  886. ;;;
  887. (defun dump-package (pkg file)
  888.   (declare (type package pkg) (type fasl-file file) (values index)
  889.        (inline assoc))
  890.   (cond ((cdr (assoc pkg (fasl-file-packages file) :test #'eq)))
  891.     (t
  892.      (unless *cold-load-dump*
  893.        (dump-fop 'lisp::fop-normal-load file))
  894.      (dump-simple-string (package-name pkg) file)
  895.      (dump-fop 'lisp::fop-package file)
  896.      (unless *cold-load-dump*
  897.        (dump-fop 'lisp::fop-maybe-cold-load file))
  898.      (let ((entry (dump-pop file)))
  899.        (push (cons pkg entry) (fasl-file-packages file))
  900.        entry))))
  901.  
  902.  
  903. ;;; Dump-Symbol  --  Internal
  904. ;;;
  905. ;;;    If we get here, it is assumed that the symbol isn't in the table, but we
  906. ;;; are responsible for putting it there when appropriate.  To avoid too much
  907. ;;; special-casing, we always push the symbol in the table, but don't record
  908. ;;; that we have done so if *Cold-Load-Dump* is true.
  909. ;;;
  910. (defun dump-symbol (s file)
  911.   (let* ((pname (symbol-name s))
  912.      (pname-length (length pname))
  913.      (pkg (symbol-package s)))
  914.  
  915.     (cond ((null pkg)
  916.        (dump-fop* pname-length lisp::fop-uninterned-small-symbol-save
  917.               lisp::fop-uninterned-symbol-save file))
  918.       ((eq pkg *package*)
  919.        (dump-fop* pname-length lisp::fop-small-symbol-save
  920.               lisp::fop-symbol-save file))
  921.       ((eq pkg ext:*lisp-package*)
  922.        (dump-fop* pname-length lisp::fop-lisp-small-symbol-save
  923.               lisp::fop-lisp-symbol-save file))
  924.       ((eq pkg ext:*keyword-package*)
  925.        (dump-fop* pname-length lisp::fop-keyword-small-symbol-save
  926.               lisp::fop-keyword-symbol-save file))
  927.       ((< pname-length 256)
  928.        (dump-fop* (dump-package pkg file)
  929.               lisp::fop-small-symbol-in-byte-package-save
  930.               lisp::fop-small-symbol-in-package-save file)
  931.        (dump-byte pname-length file))
  932.       (t
  933.        (dump-fop* (dump-package pkg file)
  934.               lisp::fop-symbol-in-byte-package-save
  935.               lisp::fop-symbol-in-package-save file)
  936.        (dump-unsigned-32 pname-length file)))
  937.  
  938.     (dump-bytes pname (length pname) file)
  939.  
  940.     (unless *cold-load-dump*
  941.       (setf (gethash s (fasl-file-eq-table file)) (fasl-file-table-free file)))
  942.  
  943.     (incf (fasl-file-table-free file)))
  944.  
  945.   (undefined-value))
  946.  
  947.  
  948. ;;; Dumper for lists.
  949.  
  950. ;;; Dump-List  --  Internal
  951. ;;;
  952. ;;;    Dump a list, setting up patching information when there are
  953. ;;; circularities.  We scan down the list, checking for CDR and CAR
  954. ;;; circularities.
  955. ;;;
  956. ;;; If there is a CDR circularity, we terminate the list with NIL and make a
  957. ;;; Circularity notation for the CDR of the previous cons.
  958. ;;;
  959. ;;; If there is no CDR circularity, then we mark the current cons and check for
  960. ;;; a CAR circularity.  When there is a CAR circularity, we make the CAR NIL
  961. ;;; initially, arranging for the current cons to be patched later.
  962. ;;;
  963. ;;; Otherwise, we recursively call the dumper to dump the current element.
  964. ;;;
  965. ;;; Marking of the conses is inhibited when *cold-load-dump* is true.  This
  966. ;;; inhibits all circularity detection.
  967. ;;;
  968. (defun dump-list (list file)
  969.   (assert (and list
  970.            (not (gethash list (fasl-file-circularity-table file)))))
  971.   (do* ((l list (cdr l))
  972.     (n 0 (1+ n))
  973.     (circ (fasl-file-circularity-table file)))
  974.        ((atom l)
  975.     (cond ((null l)
  976.            (terminate-undotted-list n file))
  977.           (t
  978.            (sub-dump-object l file)
  979.            (terminate-dotted-list n file))))
  980.     (declare (type index n))
  981.     (let ((ref (gethash l circ)))
  982.       (when ref
  983.     (push (make-circularity :type :rplacd  :object list  :index (1- n)
  984.                 :value l  :enclosing-object ref)
  985.           *circularities-detected*)
  986.     (terminate-undotted-list n file)
  987.     (return)))
  988.  
  989.     (unless *cold-load-dump*
  990.       (setf (gethash l circ) list))
  991.  
  992.     (let* ((obj (car l))
  993.        (ref (gethash obj circ)))
  994.       (cond (ref
  995.          (push (make-circularity :type :rplaca  :object list  :index n
  996.                      :value obj  :enclosing-object ref)
  997.            *circularities-detected*)
  998.          (sub-dump-object nil file))
  999.         (t
  1000.          (sub-dump-object obj file))))))
  1001.  
  1002.  
  1003. (defun terminate-dotted-list (n file)
  1004.   (declare (type index n) (type fasl-file file))
  1005.   (case n
  1006.     (1 (dump-fop 'lisp::fop-list*-1 file))
  1007.     (2 (dump-fop 'lisp::fop-list*-2 file))
  1008.     (3 (dump-fop 'lisp::fop-list*-3 file))
  1009.     (4 (dump-fop 'lisp::fop-list*-4 file))
  1010.     (5 (dump-fop 'lisp::fop-list*-5 file))
  1011.     (6 (dump-fop 'lisp::fop-list*-6 file))
  1012.     (7 (dump-fop 'lisp::fop-list*-7 file))
  1013.     (8 (dump-fop 'lisp::fop-list*-8 file))
  1014.     (T (do ((nn n (- nn 255)))
  1015.        ((< nn 256)
  1016.         (dump-fop 'lisp::fop-list* file)
  1017.         (dump-byte nn file))
  1018.      (declare (type index nn))
  1019.      (dump-fop 'lisp::fop-list* file)
  1020.      (dump-byte 255 file)))))
  1021.  
  1022. ;;; If N > 255, must build list with one list operator, then list* operators.
  1023.  
  1024. (defun terminate-undotted-list (n file)
  1025.   (declare (type index n) (type fasl-file file))
  1026.   (case n
  1027.     (1 (dump-fop 'lisp::fop-list-1 file))
  1028.     (2 (dump-fop 'lisp::fop-list-2 file))
  1029.     (3 (dump-fop 'lisp::fop-list-3 file))
  1030.     (4 (dump-fop 'lisp::fop-list-4 file))
  1031.     (5 (dump-fop 'lisp::fop-list-5 file))
  1032.     (6 (dump-fop 'lisp::fop-list-6 file))
  1033.     (7 (dump-fop 'lisp::fop-list-7 file))
  1034.     (8 (dump-fop 'lisp::fop-list-8 file))
  1035.     (T (cond ((< n 256)
  1036.           (dump-fop 'lisp::fop-list file)
  1037.           (dump-byte n file))
  1038.          (t (dump-fop 'lisp::fop-list file)
  1039.         (dump-byte 255 file)
  1040.         (do ((nn (- n 255) (- nn 255)))
  1041.             ((< nn 256)
  1042.              (dump-fop 'lisp::fop-list* file)
  1043.              (dump-byte nn file))
  1044.           (declare (type index nn))
  1045.           (dump-fop 'lisp::fop-list* file)
  1046.           (dump-byte 255 file)))))))
  1047.  
  1048.  
  1049. ;;;; Array dumping:
  1050.  
  1051. ;;; DUMP-ARRAY  --  Internal.
  1052. ;;;
  1053. ;;; Dump the array thing.
  1054. ;;;
  1055. (defun dump-array (x file)
  1056.   (if (vectorp x)
  1057.       (dump-vector x file)
  1058.       (dump-multi-dim-array x file)))
  1059.  
  1060. ;;; DUMP-VECTOR  --  Internal.
  1061. ;;;
  1062. ;;; Dump the vector object.  If it's not simple, then actually dump a simple
  1063. ;;; version of it.  But we enter the original in the EQ or EQUAL tables.
  1064. ;;; 
  1065. (defun dump-vector (x file)
  1066.   (let ((simple-version (if (array-header-p x)
  1067.                 (coerce x 'simple-array)
  1068.                 x)))
  1069.     (typecase simple-version
  1070.       (simple-base-string
  1071.        (unless (equal-check-table x file)
  1072.      (dump-simple-string simple-version file)
  1073.      (equal-save-object x file)))
  1074.       (simple-vector
  1075.        (dump-simple-vector simple-version file)
  1076.        (eq-save-object x file))
  1077.       ((simple-array single-float (*))
  1078.        (dump-single-float-vector simple-version file)
  1079.        (eq-save-object x file))
  1080.       ((simple-array double-float (*))
  1081.        (dump-double-float-vector simple-version file)
  1082.        (eq-save-object x file))
  1083.       (t
  1084.        (dump-i-vector simple-version file)
  1085.        (eq-save-object x file)))))
  1086.  
  1087. ;;; DUMP-SIMPLE-VECTOR  --  Internal
  1088. ;;;
  1089. ;;;    Dump a SIMPLE-VECTOR, handling any circularities.
  1090. ;;;
  1091. (defun dump-simple-vector (v file)
  1092.   (declare (type simple-vector v) (type fasl-file file))
  1093.   (note-potential-circularity v file)
  1094.   (do ((index 0 (1+ index))
  1095.        (length (length v))
  1096.        (circ (fasl-file-circularity-table file)))
  1097.       ((= index length)
  1098.        (dump-fop* length lisp::fop-small-vector lisp::fop-vector file))
  1099.     (let* ((obj (aref v index))
  1100.        (ref (gethash obj circ)))
  1101.       (cond (ref
  1102.          (push (make-circularity :type :svset  :object v  :index index
  1103.                      :value obj  :enclosing-object ref)
  1104.            *circularities-detected*)
  1105.          (sub-dump-object nil file))
  1106.         (t
  1107.          (sub-dump-object obj file))))))
  1108.  
  1109. ;;; DUMP-SIMPLE-STRING  --  Internal
  1110. ;;;
  1111. ;;;    Dump a SIMPLE-BASE-STRING.
  1112. ;;;
  1113. (defun dump-simple-string (s file)
  1114.   (declare (type simple-base-string s))
  1115.   (let ((length (length s)))
  1116.     (dump-fop* length lisp::fop-small-string lisp::fop-string file)
  1117.     (dump-bytes s length file))
  1118.   (undefined-value))
  1119.  
  1120. ;;; DUMP-I-VECTOR  --  Internal
  1121. ;;;
  1122. ;;; *** NOT *** the FOP-INT-VECTOR as currently documented in rtguts.  Size
  1123. ;;; must be a directly supported I-vector element size, with no extra bits.
  1124. ;;;
  1125. ;;; If a byte vector, or if the native and target byte orderings are the same,
  1126. ;;; then just write the bits.  Otherwise, dispatch off of the target byte order
  1127. ;;; and write the vector one element at a time.
  1128. ;;;
  1129. (defun dump-i-vector (vec file &optional data-only)
  1130.   (declare (type (simple-array * (*)) vec))
  1131.   (let* ((ac (etypecase vec
  1132.            (simple-bit-vector 0)
  1133.            ((simple-array (unsigned-byte 2) (*)) 1)
  1134.            ((simple-array (unsigned-byte 4) (*)) 2)
  1135.            ((simple-array (unsigned-byte 8) (*)) 3)
  1136.            ((simple-array (unsigned-byte 16) (*)) 4)
  1137.            ((simple-array (unsigned-byte 32) (*)) 5)))
  1138.      (len (length vec))
  1139.      (size (ash 1 ac))
  1140.      (bytes (ash (+ (the index (ash len ac)) 7) -3)))
  1141.     (declare (type index ac len size bytes))
  1142.     (unless data-only
  1143.       (dump-fop 'lisp::fop-int-vector file)
  1144.       (dump-unsigned-32 len file)
  1145.       (dump-byte size file))
  1146.     (dump-data-maybe-byte-swapping vec bytes size file)))
  1147.  
  1148. ;;; DUMP-SINGLE-FLOAT-VECTOR  --  internal.
  1149. ;;; 
  1150. (defun dump-single-float-vector (vec file)
  1151.   (let ((length (length vec)))
  1152.     (dump-fop 'lisp::fop-single-float-vector file)
  1153.     (dump-unsigned-32 length file)
  1154.     (dump-data-maybe-byte-swapping vec (* length vm:word-bytes)
  1155.                    vm:word-bytes file)))
  1156.  
  1157. ;;; DUMP-DOUBLE-FLOAT-VECTOR  --  internal.
  1158. ;;; 
  1159. (defun dump-double-float-vector (vec file)
  1160.   (let ((length (length vec)))
  1161.     (dump-fop 'lisp::fop-double-float-vector file)
  1162.     (dump-unsigned-32 length file)
  1163.     (dump-data-maybe-byte-swapping vec (* length vm:word-bytes 2)
  1164.                    (* vm:word-bytes 2) file)))
  1165.  
  1166. ;;; DUMP-DATA-BITS-MAYBE-BYTE-SWAPPING  --  internal.
  1167. ;;;
  1168. ;;; Dump BYTES of data from DATA-VECTOR (which must be some unboxed vector)
  1169. ;;; byte-swapping if necessary.
  1170. ;;; 
  1171. (defun dump-data-maybe-byte-swapping (data-vector bytes element-size file)
  1172.   (declare (type (simple-array * (*)) data-vector)
  1173.        (type unsigned-byte bytes)
  1174.        (type (integer 1) element-size))
  1175.   (cond ((or (eq (backend-byte-order *backend*)
  1176.          (backend-byte-order *native-backend*))
  1177.          (= element-size vm:byte-bits))
  1178.      (dump-bytes data-vector bytes file))
  1179.     ((>= element-size vm:word-bits)
  1180.      (let ((words-per-element (/ element-size vm:word-bits))
  1181.            (result (make-array bytes :element-type '(unsigned-byte 8))))
  1182.        (declare (type (integer 1 #.most-positive-fixnum)
  1183.               words-per-element))
  1184.        (dotimes (index (the integer (/ bytes words-per-element)))
  1185.          (dotimes (offset words-per-element)
  1186.            (let ((word (%raw-bits data-vector
  1187.                       (+ (* index words-per-element)
  1188.                      vm:vector-data-offset
  1189.                      (1- words-per-element)
  1190.                      (- offset)))))
  1191.          (setf (%raw-bits result (+ (* index words-per-element)
  1192.                         vm:vector-data-offset
  1193.                         offset))
  1194.                (logior (ash (ldb (byte 8 0) word) 24)
  1195.                    (ash (ldb (byte 8 8) word) 16)
  1196.                    (ash (ldb (byte 8 16) word) 8)
  1197.                    (ldb (byte 8 24) word))))))
  1198.        (dump-bytes result bytes file)))
  1199.     ((> element-size vm:byte-bits)
  1200.      (let* ((bytes-per-element (/ element-size vm:byte-bits))
  1201.         (elements (/ bytes bytes-per-element))
  1202.         (result (make-array elements
  1203.                     :element-type
  1204.                     `(unsigned-byte ,element-size))))
  1205.        (declare (type (integer 1 #.most-positive-fixnum)
  1206.               bytes-per-element)
  1207.             (type unsigned-byte elements))
  1208.        (dotimes (index elements)
  1209.          (let ((element (aref data-vector index))
  1210.            (new-element 0))
  1211.            (dotimes (i bytes-per-element)
  1212.          (setf new-element
  1213.                (logior (ash new-element vm:byte-bits)
  1214.                    (ldb (byte vm:byte-bits 0) element)))
  1215.          (setf element (ash element (- vm:byte-bits))))
  1216.            (setf (aref result index) new-element)))
  1217.        (dump-bytes result bytes file)))
  1218.     (t
  1219.      (let* ((elements-per-byte (/ vm:byte-bits element-size))
  1220.         (elements (* bytes elements-per-byte))
  1221.         (len (length data-vector))
  1222.         (result (make-array elements
  1223.                     :element-type
  1224.                     `(unsigned-byte ,element-size))))
  1225.        (dotimes (index elements)
  1226.          (multiple-value-bind (byte-index additional)
  1227.                   (truncate index elements-per-byte)
  1228.            (let ((src-idx (+ byte-index
  1229.                  (- elements-per-byte additional 1))))
  1230.          (setf (aref result index)
  1231.                (if (>= src-idx len)
  1232.                0
  1233.                (aref data-vector src-idx))))))
  1234.        (dump-bytes result bytes file)))))
  1235.  
  1236. ;;; Dump-Multi-Dim-Array  --  Internal
  1237. ;;;
  1238. ;;; Dump a multi-dimensional array.  Note: any displacements are folded out.
  1239. ;;;
  1240. (defun dump-multi-dim-array (array file)
  1241.   (let ((rank (array-rank array)))
  1242.     (dotimes (i rank)
  1243.       (dump-integer (array-dimension array i) file))
  1244.     (lisp::with-array-data ((vector array) (start) (end))
  1245.       (if (and (= start 0) (= end (length vector)))
  1246.       (sub-dump-object vector file)
  1247.       (sub-dump-object (subseq vector start end) file)))
  1248.     (dump-fop 'lisp::fop-array file)
  1249.     (dump-unsigned-32 rank file)
  1250.     (eq-save-object array file)))
  1251.  
  1252.  
  1253. ;;; Dump a character.
  1254.  
  1255. (defun dump-character (ch file)
  1256.   (dump-fop 'lisp::fop-short-character file)
  1257.   (dump-byte (char-code ch) file))
  1258.  
  1259.  
  1260. ;;; Dump a structure.
  1261.  
  1262. (defun dump-structure (struct file)
  1263.   (when *dump-only-valid-structures*
  1264.     (unless (gethash struct (fasl-file-valid-structures file))
  1265.       (error "Attempt to dump invalid structure:~%  ~S~%How did this happen?"
  1266.          struct)))
  1267.   (note-potential-circularity struct file)
  1268.   (do ((index 0 (1+ index))
  1269.        (length (structure-length struct))
  1270.        (circ (fasl-file-circularity-table file)))
  1271.       ((= index length)
  1272.        (dump-fop* length lisp::fop-small-struct lisp::fop-struct file))
  1273.     (let* ((obj (structure-ref struct index))
  1274.        (ref (gethash obj circ)))
  1275.       (cond (ref
  1276.          (push (make-circularity :type :struct-set
  1277.                      :object struct
  1278.                      :index index
  1279.                      :value obj
  1280.                      :enclosing-object ref)
  1281.            *circularities-detected*)
  1282.          (sub-dump-object nil file))
  1283.         (t
  1284.          (sub-dump-object obj file))))))
  1285.  
  1286.